﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using VersionComparer.Base;
using VersionComparer.Comparer;
using VersionComparer.DataModel.Assemblies.Images;

namespace VersionComparer.DataModel.Assemblies
{
    [Serializable]
    public abstract class MethodBaseItem<T>: AssemblyItemBase<T>
        where T : MethodBase
    {
        string matchingValue;
        CodeItem  codeItem;
        protected virtual MethodBody MethodBody(T value)
        {
            try
            {
                return value.GetMethodBody();
            }
            catch
            {
                return null;
            }
        }
        protected virtual string ReturnType ( T value, bool fullNamespace)
        {
            return "";
        }
        protected string GetParametersTypesForMatching(T value)
        {
            StringBuilder parameters = new StringBuilder();
            List<ParameterItem> parameterItems = new List<ParameterItem>(GetChilds().OfType<ParameterItem>());

            parameters.Append(parameterItems.Count.ToString());
            for (int i = 0; i < parameterItems.Count; i++)
                parameters.AppendFormat(" , {0}", parameterItems[i].UnderlyingTypeName);

            return parameters.ToString();
        }
        protected string GetParametersCode(T value, bool fullNamespace)
        {
            StringBuilder parameters = new StringBuilder();
            List<ParameterItem> parameterItems = new List<ParameterItem>(GetChilds().OfType<ParameterItem>());
            bool isFirst = true;
            for (int i = 0; i < parameterItems.Count; i++)
            {
                if (!isFirst)
                    parameters.Append(" , ");
                parameters.Append(fullNamespace ? parameterItems[i].FullText : parameterItems[i].Text);
                isFirst = false;
            }
            return parameters.ToString();
        }
        protected override void Initialize(T value)
        {
            base.Initialize(value);
            
            Type baseType = value.DeclaringType.BaseType;
            Name = GetName(value);
            if (baseType != null)
                IsOverride = baseType.GetMethod(Name, BindingFlags.Instance | BindingFlags.Instance | BindingFlags.NonPublic) != null;
            else
                IsOverride = false;
            
            IsVirtual = value.IsVirtual && !value.IsFinal;
            IsPublic = value.IsPublic;
            IsStatic = value.IsStatic;
            IsAssembly = value.IsAssembly;
            IsAbstract = value.IsAbstract;
            IsFamilyOrAssembly = value.IsFamilyOrAssembly;
            IsFamily = value.IsFamily;
            IsAbstract = value.IsAbstract;
            matchingValue = string.Format("{0}({1})",Name, GetParametersTypesForMatching(value));
            Text = string.Format("{0}{3} {1}({2})", AccessorsAsCode, Name, GetParametersCode ( value, false), ReturnType(value, false));
            IsOverride = value.DeclaringType != value.ReflectedType;
        }
        protected virtual string GetName(T value)
        {
            return value.Name;
        }
        
        protected override string GetFullText(T value)
        {
            
            return string.Format("{0}{3} {1}({2})", AccessorsAsCode, Name, GetParametersCode(value, true), UnderlyingTypeRtf.Text );
        }
        protected override ComparableItem[] GetChilds(T value)
        {
            List<ComparableItem> childs = new List<ComparableItem>();
            //childs.Add ( new ValueItem(this, "ReturnValue" , value.
            var parameters = value.GetParameters();
            foreach (var parameter in parameters)
                childs.Add(Create<ParameterItem, ParameterInfo>(parameter));

            codeItem = Create<CodeItem, MethodBody>(MethodBody(value));
            childs.Add(codeItem);

            return childs.ToArray ();
        }
        public virtual bool ShowParameters
        {
            get
            {
                return true;
            }
        }
        protected void BuildParametersRtf(RtfBuilder builder, bool differencesOnly, bool useParentColor)
        {
            List<ParameterItem> parameterItems = new List<ParameterItem>(GetChilds().OfType<ParameterItem>());
            bool isFirst = true;
            for (int i = 0; i < parameterItems.Count; i++)
            {

                if (!isFirst)
                    builder.Append(" , ");
                parameterItems[i].GetAsRtf(builder, differencesOnly, useParentColor);
                isFirst = false;
            }
            
        }
        protected override void BuildRtf(Base.RtfBuilder builder, bool differencesOnly, bool useParentColor)
        {
            BuildAttributesRtf(builder, differencesOnly, useParentColor);
            builder.Append(AccessorsAsCode, keywordColor);
            builder.Append(UnderlyingTypeRtf);
            if (UnderlyingTypeRtf.Text.Length > 0)
                builder.Append(" ");
            builder.Append(string.Format ( "{0}( ",Name));
            BuildParametersRtf(builder, differencesOnly, useParentColor);
                builder.AppendLine(")");
            
            builder.AppendLine("{");
            builder.Ident();
            if ( codeItem != null )
                codeItem.GetAsRtf(builder, differencesOnly, useParentColor);
            builder.DeIdent();
            builder.AppendLine("\r\n}");
        }
        protected override System.Drawing.Image GetSpecificImage()
        {
            return AssemblyResources.method;
        }

        protected override int HashCodeForMatch
        {
            get
            {
                return matchingValue.GetHashCode();
            }
        }

        protected override int CompareToItem(ComparableItem other)
        {
            return matchingValue.CompareTo((other as MethodBaseItem<T>).matchingValue);
        }

        public override double Matches(ComparisonAlgorithm algorithm, ComparableItem other)
        {
             MethodBaseItem<T> otherItem = (other as MethodBaseItem<T>);
             if (matchingValue == otherItem.matchingValue)
                return Match.CertainMatch;
             return Match.MatchStrings(ComparisonAlgorithm.Thorough, Name, otherItem.Name, false);
        }

        public override Difference DifferenceRelativeTo(ComparableItem otherItem)
        {
            if (otherItem.FullText == FullText)
                return Difference.None;
            else
            {
                return Difference.Value;
            }
        }

    }
}
